/*
Copyright (c) 2023 China Mobile Information Technology Co., Ltd
OpenGauss Operator is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
         http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/

package controller

import (
	"context"
	"fmt"
	v1 "k8s.io/api/batch/v1"
	"k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/runtime"
	gsv1 "openGauss-operator/api/v1"
	customClient "openGauss-operator/internal/client"
	"openGauss-operator/internal/service"
	ctrl "sigs.k8s.io/controller-runtime"
	"sigs.k8s.io/controller-runtime/pkg/handler"
	"sigs.k8s.io/controller-runtime/pkg/log"
	"sigs.k8s.io/controller-runtime/pkg/reconcile"
	"sigs.k8s.io/controller-runtime/pkg/source"
	"time"
)

// OpenGaussBackupRecoveryReconciler reconciles a OpenGaussBackupRecovery object
type OpenGaussBackupRecoveryReconciler struct {
	K8sClient      customClient.K8sClient
	Scheme         *runtime.Scheme
	backupRecovery service.BackupRecoveryInterface
}

//+kubebuilder:rbac:groups=gaussdb.gaussdb.middleware.cmos.cn,resources=opengaussbackuprecoveries,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=gaussdb.gaussdb.middleware.cmos.cn,resources=opengaussbackuprecoveries/status,verbs=get;update;patch
//+kubebuilder:rbac:groups=gaussdb.gaussdb.middleware.cmos.cn,resources=opengaussbackuprecoveries/finalizers,verbs=update

// Reconcile is part of the main kubernetes reconciliation loop which aims to
// move the current state of the cluster closer to the desired state.
// the OpenGaussBackupRecovery object against the actual cluster state, and then
// perform operations to make the cluster state reflect the state specified by
// the user.
//
// For more details, check Reconcile and its Result here:
// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.14.4/pkg/reconcile
func (r *OpenGaussBackupRecoveryReconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.Result, error) {

	logger := log.FromContext(ctx)
	startTime := time.Now()

	// Get OpenGaussBackupRecovery Object
	br, err := r.K8sClient.GetOpenGaussBackupRecovery(request.NamespacedName)
	if err != nil {
		if errors.IsNotFound(err) {
			logger.Info("OpenGaussBackupRecovery resource not found. Ignoring since object must be deleted")
			return reconcile.Result{}, nil
		}
		logger.Error(err, "Failed to get OpenGaussBackupRecovery")
		return reconcile.Result{}, err
	}

	logger.Info("Started syncing OpenGaussBackupRecovery ")
	defer func() {
		logger.Info("Finished syncing OpenGaussBackupRecovery " + fmt.Sprintf("%s", time.Since(startTime)))
	}()

	if err := r.backupRecovery.ReconcileBrBackupRecovery(br); err != nil {
		return ctrl.Result{}, err
	}

	return ctrl.Result{}, nil
}

// SetupWithManager sets up the controller with the Manager.
func (r *OpenGaussBackupRecoveryReconciler) SetupWithManager(mgr ctrl.Manager) error {
	r.backupRecovery = service.NewBackupRecovery(r.K8sClient)
	return ctrl.NewControllerManagedBy(mgr).
		For(&gsv1.OpenGaussBackupRecovery{}).
		Watches(&source.Kind{Type: &v1.Job{}}, handler.Funcs{
			CreateFunc:  nil,
			UpdateFunc:  JobUpdateHandler,
			DeleteFunc:  nil,
			GenericFunc: nil,
		}).
		WithEventFilter(&ResourceLabelPredicate{}).
		Complete(r)
}
